import { Injectable } from '@angular/core';
import { registerLocaleData, formatDate } from '@angular/common';
import { cloneDeep } from 'lodash';
import { isValid, parse, Locale } from 'date-fns';
import { enUS, zhCN } from 'date-fns/locale';
import { zhcn, extra } from '../calendar-base/zhcn.package';
import { LvConfig } from '../config';

const FormatOptions = {
  short: 'M/d/yy, h:mm a',
  medium: 'MMM d, y, h:mm:ss a',
  long: 'MMMM d, y, h:mm:ss a z',
  full: 'EEEE, MMMM d, y, h:mm:ss a zzzz',
  shortDate: 'M/d/yy',
  mediumDate: 'MMM d, y',
  longDate: 'MMMM d, y',
  fullDate: 'EEEE, MMMM d, y',
  shortTime: 'h:mm a',
  mediumTime: 'h:mm:ss a',
  longTime: 'h:mm:ss a z',
  fullTime: 'h:mm:ss a zzzz',
};

@Injectable({
  providedIn: 'root',
})
export class DateService {
  constructor() {
    // 注册中文语言包
    registerLocaleData(zhcn, 'zh-cn', extra);
  }

  /**
   * 检验输入的date是否是时间类型
   */
  isValidDate(date: Date): boolean {
    return isValid(date);
  }

  getLocale(): Locale {
    return LvConfig.language === 'zh-cn' ? zhCN : enUS;
  }

  /**
   * 根据传入的formatter解析时间字符串
   * @param value 时间字符串
   * @param format 时间格式化（暂时不支持中文环境下angular DatePipe的传入方法）
   */
  parseDate(value: string, fmt: string): Date {
    let format = fmt;
    format = FormatOptions[format] ? FormatOptions[format] : format;
    return parse(value, format, new Date(), { locale: this.getLocale() });
  }

  /**
   * 获取时区偏移后的日期时间
   * @param timezoneOffset 时区偏移值（分钟）
   */
  getTimezoneOffsetDate(date, timezoneOffset, reverse = false): any {
    if (!(date instanceof Date)) {
      return date;
    }

    const d = cloneDeep(date);
    const k = reverse ? 1 : -1;
    const localTimezoneOffset = d.getTimezoneOffset();
    const minutes = k * (localTimezoneOffset - timezoneOffset);
    return new Date(d.setMinutes(d.getMinutes() + minutes));
  }

  /**
   * Date格式化
   * @param date 时间戳
   * @param format 格式化字符串 或者 自定义格式化function
   * @param timezoneOffset 时区偏移值（分钟）
   */
  format(date: Date, format: string | ((date: Date) => string), timezoneOffset?: number): string {
    const timezone = this.getTimezone(timezoneOffset);
    let result = '';
    if (!date) {
      return result;
    }
    if (typeof format === 'function') {
      result = format(date);
    } else {
      result = formatDate(date, format, LvConfig.language, timezone);
    }
    return result;
  }

  /**
   * 根据时区偏移分钟数获取时区
   * @param timezoneOffset 时区偏移值（分钟）
   */
  getTimezone(timezoneOffset: number): string {
    if (!timezoneOffset && timezoneOffset !== 0) {
      return undefined;
    }
    const hours = parseInt(Math.abs(timezoneOffset / 60).toString());
    const minites = Math.abs(timezoneOffset % 60);
    const prefix = timezoneOffset >= 0 ? '-' : '+';
    const hourStr = hours < 10 ? `0${hours}` : hours.toString();
    const miniteStr = minites < 10 ? `0${minites}` : minites.toString();
    return prefix + hourStr + miniteStr;
  }
}
